package app.displayTree.analyze {
    import app.debug.APPLog;
    import app.displayTree.fixer.shape.ShapeMetaWarp;
    import app.displayTree.fixer.text.TextFieldMetaWrap;
    import app.displayTree.special.SpecialSymbolManger;
    import app.utils.MetaInfoUtils;

    import copyengine.infoTree.meta.CESAnimationEachFrameInfoMeta;
    import copyengine.infoTree.meta.CESDisplayObjectMeta;
    import copyengine.infoTree.meta.CESMovieClipMeta;
    import copyengine.infoTree.meta.CESShapeMeta;
    import copyengine.infoTree.meta.CESSpriteMeta;
    import copyengine.infoTree.meta.CESTextFieldMeta;
    import copyengine.infoTree.meta.CESTextureMeta;

    import flash.display.DisplayObject;
    import flash.display.MorphShape;
    import flash.display.MovieClip;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.text.StaticText;
    import flash.text.TextField;
    import flash.utils.Dictionary;

    /**
     * Mc分析的入口 用于持续分析传入的Mc 并且将分析的结果存储于相应的变量中
     */
    public final class DisplayTreeAnalyst {
        //存储所有的ShapeMeta 用于后面的Fix
        private var mAllShapeMetaWarpVector:Vector.<ShapeMetaWarp>;
        //存储所有的TextFieldMeta 用于后面的Fix
        private var mAllTextFieldMetaWrapVector:Vector.<TextFieldMetaWrap>;

        private var mSupport:DisplayTreeAnalyzeSupport;

        //Hold所有需要Special对待的Mc
        private var mSpecialSymbolManger:SpecialSymbolManger;

        //用于检测一个Mc是否可以直接忽略其内部解析(详情见该类的注释)
        private var mFlattenSpriteTester:FlattenSpriteTester;

        public function DisplayTreeAnalyst() {
            mAllShapeMetaWarpVector = new Vector.<ShapeMetaWarp>();
            mAllTextFieldMetaWrapVector = new Vector.<TextFieldMetaWrap>();
            mSupport = new DisplayTreeAnalyzeSupport();
            mFlattenSpriteTester = new FlattenSpriteTester();
        }

        public function setSpecialSymbolManger(_manger:SpecialSymbolManger):void {
            mSpecialSymbolManger = _manger;
            mFlattenSpriteTester.initialize(mSpecialSymbolManger, mSupport);
        }


        /**
         * 清除当前在Analyst里面存储的所有纹理信息,对于非ShareTexture的文件
         * 每分析完一个Mc都要清除一次Analyst, 注意! 每次并不清除SpecialSymbolManger
         */
        public function clean():void {
            mAllShapeMetaWarpVector = new Vector.<ShapeMetaWarp>();
            mAllTextFieldMetaWrapVector = new Vector.<TextFieldMetaWrap>();
            mSupport.clean();
        }

        /**
         * 返回当前存储在Analyst里面的所有纹理信息
         */
        public function getAllExportTextureBitmapDic():Dictionary { return mSupport.exportTextureBitmapDic(); }

        /**
         *返回所有需要调整信息的ShapeWarp
         */
        public function getAllShapeMetaWarpVector():Vector.<ShapeMetaWarp> { return mAllShapeMetaWarpVector; }

        /**
         *返回所有需要调整信息的TextFieldMetaWrap
         */
        public function getAllTextFieldMetaWrapVector():Vector.<TextFieldMetaWrap> { return mAllTextFieldMetaWrapVector; }

        /**
         * 返回所有需要调整的TextureMeta,@see TextureMetaFixer
         */
        public function getAllTextureMetaVector():Vector.<CESTextureMeta> { return mSupport.exportAllTextureMetaVector(); }

        //=============================================//
        //==============      ANALYZE      ====================//
        //=============================================//

        /**
         *分析一个显示对象,并返回该对象的Meta信息</br>
         * <b>注意!!此时未返回对应纹理信息</b>
         * 如果需要纹理信息,需要调用getAllTextureDic函数
         */
        public function analyze(_target:DisplayObject):CESDisplayObjectMeta {
            if (_target is MovieClip) {
                if ((_target as MovieClip).totalFrames == 1) {
                    return doAnalyzeSprite(_target as Sprite);
                }
                else {
                    return doAnalyzeMovieClip(_target as MovieClip);
                }
            }
            else if (_target is Shape) {
                return doAnalyzeShape(_target as Shape);
            }
            else if (_target is TextField || _target is StaticText) {
                return doAnalyzeTextField(_target as TextField);
            }
            else if (_target is MorphShape) {
                APPLog.err("Find one target is MorphShape--->Can not analyze MorphShape data ,as i can't get the right bound of infoTree");
                throw new Error("");
            }
            else {
                APPLog.err("unknown target type");
                return null;
            }
        }


        private function doAnalyzeMovieClip(_target:MovieClip):CESMovieClipMeta {
            var mcMeta:CESMovieClipMeta = new CESMovieClipMeta();
            mcMeta.allTargetMetaArray = [];
            mcMeta.mKeyAndIndexMapDic = {};

            var totalFrame:int = _target.totalFrames;
            for (var currentFrame:int = totalFrame; currentFrame > 0; currentFrame--) {
                _target.gotoAndStop(currentFrame);

                //===Push帧标签
                _target.currentFrameLabel != null ? mcMeta.mKeyAndIndexMapDic[_target.currentFrameLabel] = currentFrame : null;

                //===遍历当前帧下每个Child
                var totalChildNum:int = _target.numChildren;
                for (var index:int = 0; index < totalChildNum; index++) {
                    var childMc:DisplayObject = _target.getChildAt(index);
                    var targetMeta:CESDisplayObjectMeta = getOrCreateAnimationTarget(childMc.name, childMc, mcMeta);
                    targetMeta.childIndex = index;
                    var currentFrameInfoMeta:CESAnimationEachFrameInfoMeta = MetaInfoUtils.getTargetFrameMatrix(childMc, currentFrame, currentFrame);

                    //尝试合并Matrix信息
                    //当一个Mc在时间轴上静止3s不动 优化后只产生一个Matrix
                    if (targetMeta.frameTransformMatrixArray.length > 0) {
                        var lastInfoMeta:CESAnimationEachFrameInfoMeta = targetMeta.frameTransformMatrixArray[targetMeta.frameTransformMatrixArray.length - 1];
                        if (lastInfoMeta.isEqual(currentFrameInfoMeta)) {
                            lastInfoMeta.merge(currentFrameInfoMeta);
                        }
                        else {
                            targetMeta.frameTransformMatrixArray.push(currentFrameInfoMeta);
                        }
                    }
                    else {
                        targetMeta.frameTransformMatrixArray.push(currentFrameInfoMeta);
                    }
                }
            }
            mcMeta.totalFrames = totalFrame;
            MetaInfoUtils.fillDisplayObjectMetaBasicInfo(_target, mcMeta);
            return mcMeta;
        }

        private function getOrCreateAnimationTarget(_name:String, _mc:DisplayObject, _meta:CESMovieClipMeta):CESDisplayObjectMeta {
            var length:int = _meta.allTargetMetaArray.length;
            for (var i:int = 0; i < length; i++) {
                var targetMeta:CESDisplayObjectMeta = _meta.allTargetMetaArray[i];
                if (targetMeta.name == _name) {
                    return targetMeta;
                }
            }
            var newTargetMeta:CESDisplayObjectMeta = analyze(_mc);
            //在MovieClip中需要丢弃Target Transfrom信息,由MovieClip读取生成
            newTargetMeta.frameTransformMatrixArray.length = 0;
            _meta.allTargetMetaArray.push(newTargetMeta);
            return newTargetMeta;
        }

        private function doAnalyzeSprite(_target:Sprite):CESDisplayObjectMeta {
            if (mFlattenSpriteTester.isCanFlattenSprite(_target)) {
                //当前Sp可以被压扁,直接Cache不再递归里面元素
                return doAnalyzeShape(_target);
            }
            else {
                var specialMeta:CESDisplayObjectMeta = mSpecialSymbolManger.tryToGenerateSpecialSymbolMeta(_target, mSupport);
                if (specialMeta == null) {
                    var spMeta:CESSpriteMeta = new CESSpriteMeta();
                    spMeta.childMetaArray = [];

                    var totalChildNum:int = _target.numChildren;
                    for (var index:int = 0; index < totalChildNum; index++) {
                        var childMc:DisplayObject = _target.getChildAt(index);

                        var childMeta:CESDisplayObjectMeta = analyze(childMc);
                        childMeta.childIndex = index;
                        spMeta.childMetaArray.push(childMeta);
                    }

                    MetaInfoUtils.fillDisplayObjectMetaBasicInfo(_target, spMeta);
                    return spMeta;
                }
                else {
                    return specialMeta;
                }
            }
        }

        private function doAnalyzeShape(_target:DisplayObject):CESDisplayObjectMeta {
            var shapeMeta:CESShapeMeta = new CESShapeMeta();
            //			mSupport.fillMetaBasicInfo(_target, shapeMeta);
            shapeMeta.textureMeta = mSupport.pushMcToExportAndReturnMcTextureInfo(_target);

            MetaInfoUtils.fillDisplayObjectMetaBasicInfo(_target, shapeMeta);

            //对于Shape存在一个Bug:
            //如果在FLA库中某一个元件A是通过 "直接复制" 的 元件B (FLA库中操作) 则元件A的坐标信息是错误的(getBound方法取得到的x,y(偏移值)不对)
            //可以理解为swf底层针对于这种 "直接复制" 做了某种优化,使得元件A的坐标信息其实反映的是把 元件B进行某种变化能够得到
            //所以这时候需要将shape重新添加到一个container里面 才可以
            //但是直接在此处进行修正则改变了显示树结构,导致递归错误(即时最后再把target add回去也不行,
            //MovieClip无解(MovieClip addChild都会放在第一帧上面,但是比如这种情况在第二帧才出现,则这种加container再放回去的操作会导致MovieClip 第一帧child数量增加),
            //所以目前的解决方案是最后再对所有Shape进行修正(修正的方式还是addChild,因为addChild以后这种由于"直接复制"产生的错误会消失)
            //@see DisplayTreeShapeFixer.fixShapeMetaProperty()
            var shapeMetaWarp:ShapeMetaWarp = new ShapeMetaWarp();
            shapeMetaWarp.shapeMeta = shapeMeta;
            shapeMetaWarp.sourceTarget = _target;
            mAllShapeMetaWarpVector.push(shapeMetaWarp);

            return shapeMeta;
        }

        private function doAnalyzeTextField(_target:TextField):CESDisplayObjectMeta {
            var textFieldMeta:CESTextFieldMeta = new CESTextFieldMeta();
            MetaInfoUtils.fillTextFieldMetaInfo(_target, textFieldMeta);

            //TextField读取的矩阵信息也有错误,详情看有道笔记
            var textFieldMetaWarp:TextFieldMetaWrap = new TextFieldMetaWrap();
            textFieldMetaWarp.textFieldMeta = textFieldMeta;
            textFieldMetaWarp.sourceTarget = _target;
            mAllTextFieldMetaWrapVector.push(textFieldMetaWarp);

            return textFieldMeta;
        }

    }
}
